﻿#define _CRT_SECURE_NO_WARNINGS 1

//指针总复习
#include<stdio.h>
#include<string.h>
//int main()// sizeof 计算变量所占内存内存空间⼤⼩的，单位是字节，如果操作数是类型的话，计算的是使⽤类型创建的变量所占内存空间的⼤⼩。包含\0
//{
//	int a = 10;
//	printf("%d\n", sizeof(a));
//	printf("%d\n", sizeof a);
//	printf("%d\n", sizeof(int));
//	return 0;
//}

//int main()
//{
//	char arr1[3] = { 'a', 'b', 'c'};
//	char arr2[ ] = "abc";
//	printf("%d\n", strlen(arr1)); //对arr1不知道\0啥时候出现，所以是随机值
//	printf("%d\n", strlen(arr2));// \0 之前字符串中字符的个数，不包括\0
//
//	printf("%d\n", sizeof(arr1));//结果3
//	printf("%d\n", sizeof(arr2));//结果4
//	return 0;
//}
// 
//int main()
//{
//	int a = 10;
//	short s = 8;
//	printf("%d\n", sizeof(s = a + 2));//s = a + 2是在运行时运算的，sizeof编译时计算，所以不会计算表达式
//	return 0;
//}

//int main()//数组名是数组首元素地址，但sizeof(数组名)，&数组名不是
//{
//	int a[] = { 1,2,3,4 };
//	printf("%zd\n", sizeof(a));//结果是16（整个数组的大小）
//	printf("%zd\n", sizeof(a + 0));//a是首元素地址(指针)，类型是int*,结果是4或8
//	printf("%zd\n", sizeof(*a));//结果是首元素1，大小是4
//	printf("%zd\n", sizeof(a + 1));//a是首元素地址(指针)，类型是int*,a+1是第二个元素地址，结果是4或8
//	printf("%zd\n", sizeof(a[1]));//结果是第二个元素2，大小是4，
//	printf("%zd\n", sizeof(&a));//整个数组的地址，整个数组的地址也是地址，类型int(*)[4]，结果是4或8
//	printf("%zd\n", sizeof(*&a));//*&a等价于sizeof(a),结果是16（整个数组的大小）
//	printf("%zd\n", sizeof(&a + 1));//&a + 1跳过整个数组后的地址，是地址结果就是4/8
//	printf("%d\n", sizeof(&a[0]));//首元素地址，结果是4/8
//	printf("%d\n", sizeof(&a[0] + 1));//第二个元素地址，结果是4/8
//	return 0;
//}


//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%d\n", sizeof(arr));//整个数组的大小，结果是6字节（char一个字节）
//	printf("%d\n", sizeof(arr + 0));//arr首元素地址,arr+0还是首元素地址，结果是4/8
//	printf("%d\n", sizeof(*arr));//首元素地址解引用，结果是1
//	printf("%d\n", sizeof(arr[1]));//第二个元素，结果是1
//	printf("%d\n", sizeof(&arr));//整个数组地址，结果是4/8
//	printf("%d\n", sizeof(&arr + 1));//&a + 1跳过整个数组后的地址，是地址结果就是4/8
//	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素地址，结果是4/8
//	return 0;
//}
//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%d\n", strlen(arr));//首元素地址，到\0结束，但不知道\0在哪里，结果是随机值
//	printf("%d\n", strlen(arr + 0));//arr + 0首元素地址，到\0结束，但不知道\0在哪里，结果是随机值
//	//printf("%d\n", strlen(*arr));//首元素‘a'，ascll是97，相当于吧97传给了strlen.不能访问，程序崩溃
//	//printf("%d\n", strlen(arr[1]));//第二个元素b,不能访问，程序崩溃
//	printf("%d\n", strlen(&arr));//&arr数组的地址，起始位置是第一个元素，结果是随机值
//	printf("%d\n", strlen(&arr + 1));//&a + 1跳过整个数组后的地址，结果是随机值
//	printf("%d\n", strlen(&arr[0] + 1));//从第二个元素开始，结果是随机值
//	return 0;
//}

//int main()
//{
//	char arr[] = "abcdef";
//	printf("%d\n", sizeof(arr));//结果是7，包括\0
//	printf("%d\n", sizeof(arr + 0));//首元素地址，结果是1
//	printf("%d\n", sizeof(*arr));//首元素。大小是1
//	printf("%d\n", sizeof(arr[1]));//第二个元素，结果是1
//	printf("%d\n", sizeof(&arr));//结果是4/8
//	printf("%d\n", sizeof(&arr + 1));//&a + 1跳过整个数组后的地址，结果是4/8
//	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素地址，结果是4/8
//	return 0;
//}
//int main()
//{
//	char arr[] = "abcdef";//有\0
//	printf("%d\n", strlen(arr));//到\0结束，结果是6
//	printf("%d\n", strlen(arr + 0));//首元素地址，到\0结束，结果是6
//	printf("%d\n", strlen(*arr));//第一个元素，出错
//	printf("%d\n", strlen(arr[1]));//报错
//	printf("%d\n", strlen(&arr));//数组的地址，也是从第一个元素开始，结果是6
//	printf("%d\n", strlen(&arr + 1));////&a + 1跳过整个数组后的地址，结果是随机值
//	printf("%d\n", strlen(&arr[0] + 1));//第二个元素开始，结果是5
//	return 0;
//}


//int main()
//{
//	char* p = "abcdef";//  \0
//	printf("%d\n", sizeof(p));//p是指针，整个字符串的地址，4/8
//	printf("%d\n", sizeof(p + 1));//p + 1是B的地址，结果是4/8
//	printf("%d\n", sizeof(*p));//*p是char类型，结果是1
//	printf("%d\n", sizeof(p[0]));//a，结果是1   p[0]=*（p+0）     常量字符串相当于数组，p是数组名
//	printf("%d\n", sizeof(&p));//取出的是p的地址
//	printf("%d\n", sizeof(&p + 1));//跳过p指针大小的地址，结果是4/8
//	printf("%d\n", sizeof(&p[0] + 1));//第二个元素的地址，结果是4/8   &p[0] 首元素地址
//	return 0;
//}
//int main()
//{
//	char* p = "abcdef";
//	printf("%d\n", strlen(p));//结果是6
//	printf("%d\n", strlen(p + 1));//结果是5
//	printf("%d\n", strlen(*p));//*p是字符a，报错
//	printf("%d\n", strlen(p[0]));//p[0]=*(p+0),报错
//	printf("%d\n", strlen(&p));//指针变量p的地址，和字符串无关，从p指针变量起始位置开始，结果随机
//	printf("%d\n", strlen(&p + 1));//随机值
//	printf("%d\n", strlen(&p[0] + 1));//结果是5
//	return 0;
//}

//int main()//二维数组
//{
//	int a[3][4] = { 0 };
//	printf("%d\n", sizeof(a));//数组名，整个数组的大小，结果是48
//	printf("%d\n", sizeof(a[0][0]));//第一行第一个元素，4个字节
//	printf("%d\n", sizeof(a[0]));//a[0]第一行的数组名，单独放到内部，第一行所有元素，结果是16
//	printf("%d\n", sizeof(a[0] + 1));//a[0]第一行的数组名，没有单独放到内部，所以这里的a[0]就是数组首元素地址&a[0][0],+1后是a[0][1]的地址，结果是4/8
//	printf("%d\n", sizeof(*(a[0] + 1)));//第一行第二个元素，结果是4
//	printf("%d\n", sizeof(a + 1));//a是二位数组命，没有单独放在内部，a表示二位数组首元素地址，也就是第一行地址，a+1是第二行地址，结果是4/8
//	printf("%d\n", sizeof(*(a + 1)));//第二行所有元素，结果是16
//	printf("%d\n", sizeof(&a[0] + 1));//&a[0]第一行的地址，+1是第二行的地址，结果是4/8
//	printf("%d\n", sizeof(*(&a[0] + 1)));//第二行地址解引用就是第二行所有元素，结果是16
//	printf("%d\n", sizeof(*a));//二位数组首元素地址，也就是第一行，解引用是第一行元素，结果是16
//	printf("%d\n", sizeof(a[3]));//无需真实存在，仅仅推断类型就可以计算长度，a[3]第四行数组名，单独放在内部，计算第四行大小，结果是16
//	return 0;
//}

//int main()// 指针运算笔试题解析
//{
//	int a[5] = { 1, 2, 3, 4, 5 };
//	int* ptr = (int*)(&a + 1);
//	printf("%d,%d", *(a + 1), *(ptr - 1));// 2   5
//	return 0;
//}

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥？
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{//指针+-运算
//	printf("%p\n", p + 0x1);//结构体指针+1跳过一个结构体 20个字节
//	printf("%p\n", (unsigned long)p + 0x1);// 0x1==1  整型+1
//	printf("%p\n", (unsigned int*)p + 0x1);//跳过4个字节
//	return 0;
//}

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式，从左到右依次执行所以放的是1，3，5，0，0，0
	int* p;
	p = a[0];//a[0]是第一行的数组名，数组名是首元素地址，&a[0][0]
	printf("%d", p[0]);//p[0]==*(p+0)
	return 0;
}